home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / fsck.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  34KB  |  1,363 lines

  1. /* fsck - file system checker        Author: Robbert van Renesse */
  2.  
  3. /* Modified by Norbert Schlenker
  4. *   Removed vestiges of standalone/DOS versions:
  5. *     - various unused variables and buffers removed
  6. *     - now uses library functions rather than private internal routines
  7. *     - bytewise structure copies replaced by structure assignment
  8. *     - fixed one bug with 14 character file names
  9. *     - other small tweaks for speed
  10. *
  11. * Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
  12. *   Removed -m option, by which fsck could be told to make a file
  13. *   system on a 360K floppy.  The code had limited utility, was buggy,
  14. *   and failed due to a bug in the ACK C compiler.  Use mkfs instead!
  15. */
  16.  
  17. #include <sys/types.h>
  18. #include <ctype.h>
  19. #include <errno.h>
  20. #include <fcntl.h>
  21. #include <limits.h>
  22. #include <stdlib.h>
  23. #include <unistd.h>
  24. #include <minix/config.h>
  25. #include <minix/const.h>
  26. #include <minix/type.h>
  27. #include "../fs/const.h"
  28. #include "../fs/type.h"
  29.  
  30. #undef printf            /* defined as printk in "../fs/const.h" */
  31.  
  32. #include <stdio.h>
  33.  
  34. #if INTEL_32BITS
  35. #define BITSHIFT      5    /* = log2(#bits(int)) */
  36. #else
  37. #define BITSHIFT      4    /* = log2(#bits(int)) */
  38. #endif
  39.  
  40. #define BITMAPSHIFT     13    /* = log2(#bits(block)); 13 means 1K blocks */
  41. #define MAXPRINT      8    /* max. number of error lines in chkmap */
  42. #define MAXDIRSIZE     5000    /* max. size of a reasonable directory */
  43. #define CINDIR        128    /* number of indirect zno's read at a time */
  44. #define CDIRECT         16    /* number of dir entries read at a time */
  45. #define BITMASK        ((1 << BITSHIFT) - 1)
  46. #define setbit(w, b)    (w[(b) >> BITSHIFT] |= 1 << ((b) & BITMASK))
  47. #define clrbit(w, b)    (w[(b) >> BITSHIFT] &= ~(1 << ((b) & BITMASK)))
  48. #define bitset(w, b)    (w[(b) >> BITSHIFT] & (1 << ((b) & BITMASK)))
  49.  
  50. #define ZONE_CT     360    /* default zones  (when making file system) */
  51. #define INODE_CT     95    /* default inodes (when making file system) */
  52.  
  53. /* DEBUG FIXME.  This and other things repeat stuff from fs, not necessarily
  54.  * identically.  This is part of a structure in fs/super.h, and old versions
  55.  * had the wrong type for s_magic.
  56.  */
  57. struct dsb {
  58.   ino_t s_ninodes;        /* # inodes on the minor device */
  59.   zone_nr s_nzones;        /* total dev size, incl. bit maps etc */
  60.   unsigned short s_imap_blocks;    /* # of blocks used by inode bit map */
  61.   unsigned short s_zmap_blocks;    /* # of blocks used by zone bit map */
  62.   zone_nr s_firstdatazone;    /* number of first data zone */
  63.   short s_log_zone_size;    /* log2 of blocks/zone */
  64.   off_t s_maxsize;        /* maximum file size on this device */
  65.   short s_magic;        /* magic number for super blocks */
  66. } sb;
  67.  
  68. #define STICKY_BIT    01000    /* not defined anywhere else */
  69.  
  70. /* Ztob gives the block address of a zone
  71.  * btoa gives the byte address of a block
  72.  */
  73. #define ztob(z)        ((block_nr) (z) << sb.s_log_zone_size)
  74. #define btoa(b)        ((long) (b) * BLOCK_SIZE)
  75. #define SCALE        ((int) ztob(1))    /* # blocks in a zone */
  76. #define FIRST        sb.s_firstdatazone    /* as the name says */
  77.  
  78. /* # blocks of each type */
  79. #define N_SUPER        1
  80. #define N_IMAP        (sb.s_imap_blocks)
  81. #define N_ZMAP        (sb.s_zmap_blocks)
  82. #define N_ILIST        ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
  83. #define N_DATA        (sb.s_nzones - FIRST)
  84.  
  85. /* Block address of each type */
  86. #define BLK_SUPER    (SUPER_BLOCK)
  87. #define BLK_IMAP    (BLK_SUPER + N_SUPER)
  88. #define BLK_ZMAP    (BLK_IMAP  + N_IMAP)
  89. #define BLK_ILIST    (BLK_ZMAP  + N_ZMAP)
  90. #define BLK_FIRST    ztob(FIRST)
  91. #define ZONE_SIZE    ((int) ztob(BLOCK_SIZE))
  92. #define NLEVEL        (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
  93.  
  94. /* Byte address of a zone/of an inode */
  95. #define zaddr(z)    btoa(ztob(z))
  96. #define inoaddr(i)    ((long) (i - 1) * INODE_SIZE + btoa(BLK_ILIST))
  97. #define INDCHUNK    (CINDIR * ZONE_NUM_SIZE)
  98. #define DIRCHUNK    (CDIRECT * DIR_ENTRY_SIZE)
  99.  
  100. char *prog, *device;        /* program name (fsck), device name */
  101. int firstcnterr;        /* is this the first inode ref cnt error? */
  102. unsigned *imap, *spec_imap;    /* inode bit maps */
  103. unsigned *zmap, *spec_zmap;    /* zone bit maps */
  104. unsigned *dirmap;        /* directory (inode) bit map */
  105. char rwbuf[BLOCK_SIZE];        /* one block buffer cache */
  106. block_nr thisblk;        /* block in buffer cache */
  107. char nullbuf[BLOCK_SIZE];    /* null buffer */
  108. nlink_t *count;            /* inode count */
  109. int changed;            /* has the diskette been written to? */
  110. struct stack {
  111.   dir_struct *st_dir;
  112.   struct stack *st_next;
  113.   char st_presence;
  114. } *ftop;
  115.  
  116. int dev;            /* file descriptor of the device */
  117.  
  118. #define DOT    1
  119. #define DOTDOT    2
  120.  
  121. /* Counters for each type of inode/zone. */
  122. int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode;
  123. int npipe, nfreezone, ztype[NLEVEL];
  124.  
  125. int repair, automatic, listing, listsuper;    /* flags */
  126. int firstlist;            /* has the listing header been printed? */
  127. unsigned part_offset;        /* sector offset for this partition */
  128. char answer[] = {"Answer questions with y or n.  Then hit RETURN"};
  129.  
  130. /* Initialize the variables used by this program. */
  131. initvars()
  132. {
  133.   register level;
  134.  
  135.   nregular = ndirectory = nblkspec = ncharspec = nbadinode = npipe = 0;
  136.   for (level = 0; level < NLEVEL; level++) ztype[level] = 0;
  137.   changed = 0;
  138.   thisblk = NO_BLOCK;
  139.   firstlist = 1;
  140.   firstcnterr = 1;
  141. }
  142.  
  143. /* Print the string `s' and exit. */
  144. void fatal(s)
  145. char *s;
  146. {
  147.   printf("%s\nfatal\n", s);
  148.   exit(-1);
  149. }
  150.  
  151. /* Test for end of line. */
  152. eoln(c)
  153. {
  154.   return(c == EOF || c == '\n' || c == '\r');
  155. }
  156.  
  157. /* Ask a question and get the answer unless automatic is set. */
  158. int yes(question)
  159. char *question;
  160. {
  161.   register c, answer;
  162.  
  163.   if (!repair) {
  164.     printf("\n");
  165.     return(0);
  166.   }
  167.   printf("%s? ", question);
  168.   if (automatic) {
  169.     printf("yes\n");
  170.     return(1);
  171.   }
  172.   fflush(stdout);
  173.   if ((c = answer = getchar()) == 'q' || c == 'Q') exit(1);
  174.   while (!eoln(c)) c = getchar();
  175.   return !(answer == 'n' || answer == 'N');
  176. }
  177.  
  178. /* Convert string to integer.  Representation is octal. */
  179. int atoo(s)
  180. register char *s;
  181. {
  182.   register int n = 0;
  183.  
  184.   while ('0' <= *s && *s < '8') {
  185.     n <<= 3;
  186.     n += *s++ - '0';
  187.   }
  188.   return n;
  189. }
  190.  
  191. /* If repairing the file system, print a prompt and get a string from user. */
  192. input(buf, size)
  193. char *buf;
  194. {
  195.   register char *p = buf;
  196.  
  197.   printf("\n");
  198.   if (repair) {
  199.     printf("--> ");
  200.     fflush(stdout);
  201.     while (--size) {
  202.         *p = getchar();
  203.         if (eoln(*p)) {
  204.             *p = 0;
  205.             return(p > buf);
  206.         }
  207.         p++;
  208.     }
  209.     *p = 0;
  210.     while (!eoln(getchar()));
  211.     return(1);
  212.   }
  213.   return(0);
  214. }
  215.  
  216. /* Allocate some memory and zero it. */
  217. char *alloc(nelem, elsize)
  218. unsigned nelem, elsize;
  219. {
  220.   char *p;
  221.  
  222.   if ((p = (char *) malloc(nelem * elsize)) == 0) fatal("out of memory");
  223.   memset(p, 0, nelem * elsize);
  224.   return(p);
  225. }
  226.  
  227. /* Print the name in a directory entry. */
  228. void printname(s)
  229. char *s;
  230. {
  231.   register n = NAME_MAX;
  232.   int c;
  233.  
  234.   do {
  235.     if ((c = *s) == 0) break;
  236.     if (!isprint(c)) c = '?';
  237.     putchar(c);
  238.     s++;
  239.   } while (--n);
  240. }
  241.  
  242. /* Print the pathname given by a linked list pointed to by `sp'.  The
  243.  * names are in reverse order.
  244.  */
  245. printrec(sp)
  246. struct stack *sp;
  247. {
  248.   if (sp->st_next != 0) {
  249.     printrec(sp->st_next);
  250.     putchar('/');
  251.     printname(sp->st_dir->d_name);
  252.   }
  253. }
  254.  
  255. /* Print the current pathname.  */
  256. printpath(mode, nlcr)
  257. {
  258.   if (ftop->st_next == 0)
  259.     putchar('/');
  260.   else
  261.     printrec(ftop);
  262.   switch (mode) {
  263.       case 1:
  264.     printf(" (ino = %u, ", ftop->st_dir->d_inum);
  265.     break;
  266.       case 2:
  267.     printf(" (ino = %u)", ftop->st_dir->d_inum);
  268.     break;
  269.   }
  270.   if (nlcr) printf("\n");
  271. }
  272.  
  273. /* Open the device.  */
  274. devopen()
  275. {
  276.   if ((dev = open(device, repair ? O_RDWR : O_RDONLY)) < 0) {
  277.     perror(device);
  278.     fatal("");
  279.   }
  280. }
  281.  
  282. /* Close the device. */
  283. devclose()
  284. {
  285.   if (close(dev) != 0) {
  286.     perror("close");
  287.     fatal("");
  288.   }
  289. }
  290.  
  291. /* Read or write a block. */
  292. devio(bno, dir)
  293. block_nr bno;
  294. {
  295.   if (dir == READING && bno == thisblk) return;
  296.   thisblk = bno;
  297.  
  298.   lseek(dev, btoa(bno), SEEK_SET);
  299.   if (dir == READING) {
  300.     if (read(dev, rwbuf, BLOCK_SIZE) == BLOCK_SIZE)
  301.         return;
  302.   } else {
  303.     if (write(dev, rwbuf, BLOCK_SIZE) == BLOCK_SIZE)
  304.         return;
  305.   }
  306.  
  307.   printf("%s: can't %s block %ld (error = 0x%x)\n", prog,
  308.          dir == READING ? "read" : "write", (long) bno, errno);
  309.   fatal("");
  310. }
  311.  
  312. /* Read `size' bytes from the disk starting at byte `offset'. */
  313. devread(offset, buf, size)
  314. long offset;
  315. char *buf;
  316. {
  317.   devio((block_nr) (offset / BLOCK_SIZE), READING);
  318.   memmove(buf, &rwbuf[(int) (offset % BLOCK_SIZE)], size);
  319. }
  320.  
  321. /* Write `size' bytes to the di